
package jpoco.android;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.provider.Contacts;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
// import android.provider.Contacts.Presence;
import android.provider.Contacts.People.ContactMethods;
import android.provider.Contacts.Organizations;
import android.util.Log;
import jpoco.client.*;

import java.util.*;

import org.apache.http.client.*;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.http.*;


/**
 * 
 * 
 *   Android Contact Manager
 * 
 *
 */
public class ContactManager
{
	private static final Long FALSE = new Long(0);
	private static final Long TRUE = new Long(1);
	
	public static final int PROTOCOL_AIM = 0;
    public static final int PROTOCOL_MSN = 1;
	public static final int PROTOCOL_YAHOO = 2;
	public static final int PROTOCOL_SKYPE = 3;
	public static final int PROTOCOL_QQ = 4;
	public static final int PROTOCOL_GOOGLE_TALK = 5;
	public static final int PROTOCOL_ICQ = 6;
	public static final int PROTOCOL_JABBER = 7;
	
	private ContentResolver resolver;
	private HttpClient httpClient;
	
	public ContactManager(ContentResolver r)
	{
		this(r, null);
	}
	
	public ContactManager(ContentResolver r, HttpClient client)
	{
		this.resolver = r;
		
		if (client == null)
		{
			this.httpClient = new DefaultHttpClient();
		}
		else
		{
			this.httpClient = client;
		}
	}
	
	protected void save(List<jpoco.client.Contact> contacts)
	{
		for (Contact c : contacts)
		{
			save(c);
		}
	}
	
	protected Uri save(jpoco.client.Contact c)
	{
		
		ContentValues values = new ContentValues();
		
		String name = Util.getDisplayName(c);
		
		values.put(People.NAME, name);
		values.put(People.SEND_TO_VOICEMAIL, FALSE);
		values.put(People.STARRED, FALSE);

		if (c.getNote() != null)
		{
			values.put(People.NOTES, c.getNote());
		}
		
		Uri contactUri = resolver.insert(Contacts.People.CONTENT_URI, values);

		Uri phoneUri = Uri.withAppendedPath(contactUri, Contacts.People.Phones.CONTENT_DIRECTORY);
		
		Uri emailUri = Uri.withAppendedPath(contactUri, ContactMethods.CONTENT_DIRECTORY);
		
		Uri addressUri = Uri.withAppendedPath(contactUri, ContactMethods.CONTENT_DIRECTORY);
		
		Uri organizationUri = Uri.withAppendedPath(contactUri, Contacts.Organizations.CONTENT_DIRECTORY);
		
		for (PhoneNumber pnumber : c.getPhoneNumbers())
		{
			ContentValues phoneValues = createContentValues(pnumber);
			resolver.insert(phoneUri, phoneValues);
		}
		
		for (Email email : c.getEmails())
		{
			ContentValues emailValues = createContentValues(email);
			resolver.insert(emailUri, emailValues);
		}
		
		for (Organization org : c.getOrganizations())
		{
			ContentValues orgValues = createContentValues(org);
			resolver.insert(organizationUri, orgValues);
		}
		
		for (Address a : c.getAddresses())
		{
			ContentValues addressValues = createContentValues(a);
			resolver.insert(addressUri, addressValues);
		}
		
		/*
		for (InstantMessagingAddress imAddress : c.getInstantMessagingAddresses())
		{
			ContentValues imValues = createContentValues(imAddress);
			resolver.insert(contactUri, imValues);
		}
		*/
		
		if (c.getThumbnailUrl() != null)
		{
			savePhoto(c.getThumbnailUrl(), contactUri);
		}
		else if (c.getPhotos().size() > 0)
		{
			savePhoto(c.getPhotos().get(0), contactUri);
		}
		
		return contactUri;
	}

	static public ContentValues createContentValues(InstantMessagingAddress imAddress)
	{
		ContentValues values = new ContentValues();
		
		values.put(ContactMethods.DATA, imAddress.getValue());
		values.put(ContactMethods.TYPE, getType(imAddress));
		values.put(ContactMethods.KIND, Contacts.KIND_IM);
		
		if (imAddress.isPrimary())
		{
			values.put(ContactMethods.ISPRIMARY, TRUE);
		}
		
		return values;

	}

	protected void savePhoto(Photo p, Uri contactUri)
	{
		try
		{
			byte[] data = p.getData();
			
			if (data == null) 
			{
				if (p.getValue() != null)
				{
					savePhoto(p.getValue(), contactUri);
				}
			}
			else
			{
				Contacts.People.setPhotoData(resolver, contactUri, data );
			}
		}
		catch (Exception ex)
		{
			Log.e(this.getClass().getName(), "unable to get contact photo", ex);
		}
	}
	
	protected void savePhoto(String url, Uri contactUri)
	{
		try
		{
			
			// send HTTP GET
			byte[] data = get(url);
			
			if (data != null)
			{
				Contacts.People.setPhotoData(resolver, contactUri, data );
			}
		}
		catch (Exception ex)
		{
			Log.e(this.getClass().getName(), "unable to get photo", ex);
		}
	}
	
	static public ContentValues createContentValues(Address a)
	{
		ContentValues values = new ContentValues();

		values.put(ContactMethods.DATA, a.getFormatted());
		values.put(ContactMethods.TYPE, getType(a));
		values.put(ContactMethods.KIND, Contacts.KIND_POSTAL);
		
		values.put(ContactMethods.ISPRIMARY, a.isPrimary() ? TRUE : FALSE);
		
		return values;
	}
	
	static public ContentValues createContentValues(Organization org)
	{
		ContentValues values = new ContentValues();

		values.put(Organizations.TYPE, getType(org));
		values.put(Organizations.COMPANY, org.getName());
		values.put(Organizations.TITLE, org.getTitle());
		
		values.put(Organizations.ISPRIMARY, org.isPrimary() ? TRUE : FALSE);
		
		return values;
	}
	
	static public int getType(Organization org)
	{
		if (org.isJob())
		{
			return Organizations.TYPE_WORK;
		}
		else
		{
			return Organizations.TYPE_OTHER;
		}
	}

	static public int getType(Address a)
	{
		if (a.isWork())
		{
			return ContactMethods.TYPE_WORK;
		}
		else if (a.isHome())
		{
			return ContactMethods.TYPE_HOME;
		}
		else
		{
			return ContactMethods.TYPE_OTHER;
		}
	}
	
	static public ContentValues createContentValues(PhoneNumber pnumber)
	{
		ContentValues values = new ContentValues();
		
		values.put(Phones.TYPE, getPhoneNumberType(pnumber));
		values.put(Phones.NUMBER, pnumber.getValue());
		if (pnumber.isPrimary())
		{
			values.put(Phones.ISPRIMARY, TRUE);
		}
		
		return values;
	}
	
	static public int getPhoneNumberType(PhoneNumber pnumber)
	{
		if (pnumber.isMobile())
		{
			return Contacts.Phones.TYPE_MOBILE;
		}
		else if (pnumber.isWork())
		{
			return Contacts.Phones.TYPE_WORK;
		}
		else if (pnumber.isFax())
		{
			return Contacts.Phones.TYPE_FAX_WORK;
		}
		else if (pnumber.isPager())
		{
			return Contacts.Phones.TYPE_PAGER;
		}
		else
		{
			return Contacts.Phones.TYPE_OTHER;
		}
	}

	static public int getEmailType(Email email)
	{
		if (email.isHome())
		{
			return ContactMethods.TYPE_HOME;
		}
		else if (email.isWork())
		{
			return ContactMethods.TYPE_WORK;
		}
		else
		{
			return ContactMethods.TYPE_OTHER;
		}
	}
	
	static public ContentValues createContentValues(Email email)
	{
		ContentValues values = new ContentValues();
		
		values.put(ContactMethods.KIND, Contacts.KIND_EMAIL);
		values.put(ContactMethods.TYPE, getEmailType(email));
		values.put(ContactMethods.DATA, email.getValue());
				
		values.put(ContactMethods.ISPRIMARY, email.isPrimary() ? TRUE : FALSE);
		
		return values;
	}
	
	static public int getType(InstantMessagingAddress imAddr)
	{
		
		if (imAddr.isAIM())
		{
			return PROTOCOL_AIM;
		}
		else if (imAddr.isGoogleTalk())
		{
			// todo : use ContactMethods.PROTOCOL_GOOGLE_TALK;
			return PROTOCOL_GOOGLE_TALK;
		}
		else if (imAddr.isICQ())
		{
			return PROTOCOL_ICQ;
		}
		else if (imAddr.isMSN())
		{
			return PROTOCOL_MSN;
		}
		else if (imAddr.isQQ())
		{
			return PROTOCOL_QQ;
		}
		else if (imAddr.isYahoo())
		{
			return PROTOCOL_YAHOO;
		}
		else if (imAddr.isSkype())
		{
			return PROTOCOL_SKYPE;
		}
		else if (imAddr.isXMPP())
		{
			return PROTOCOL_JABBER;
		}
		else
		{
			return -1;
		}
	}

	public void saveAsync(final List<Contact> contacts)

	{
		
		Runnable save = new Runnable()
		{
			public void run()
			{
				try
				{
					ContactManager.this.save(contacts);
				}
				catch (Throwable t)
				{
					// todo - improve this
					t.printStackTrace();
				}
			}
		
		};
		
		Thread t = new Thread(save);
		t.setName("ContactManager save contacts thread");
		t.start();
	}

	protected byte[] get(String url)
	{
		HttpGet get = null;
		HttpResponse response = null;
		HttpEntity entity = null;
		byte[] data = null;
		
		try
		{
			get = new HttpGet(url);
			response = httpClient.execute(get);
			entity = response.getEntity();
			data = EntityUtils.toByteArray(entity);
		}
		catch (Exception ex)
		{
			throw new RuntimeException(ex);
		}
		
		if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
		{
			return data;
		}
		else
		{
			throw new RuntimeException("HTTP GET failed ("
							+ url
							+ "), status code = " 
							+ response.getStatusLine().getStatusCode());
		}
		
	}

}
